//Platform unrelated librarys.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <cstdio>

// Platform related librarys.
#include <windows.h>
#include <process.h>
#include <psapi.h>
#include <tlhelp32.h>

using namespace std;

#undef UNICODE
#undef _UNICODE

#pragma comment(lib, "psapi.lib")

#define _JUDGE_DEBUG_
#define _LOGON_HNUJUDGE_USER_
#define _STRICT_PROGRAM_

#ifdef _JUDGE_DEBUG_
#define JudgeDebug( Express ) Express
#else
#define JudgeDebug( Express )
#endif

/* solution login user name and password */
char szLoginUserName[100];
char szLoginPassword[100];

typedef vector<string> svector;
typedef svector::iterator sitr;

//static DWORD  cnstRuntimeLevel = 100;
static int    cnstMaxSpjTimeLimit   = 100 * 1000;       //100s.
static int    cnstMaxOutputFileSize = 10000;			//Maxsize of output limit to Subprocess
static int    cnstMaxKernelTime = 20;					//Reserved
static int    cnstMaxCompileTime = 20 * 1000;			//Max compile time as 20 s.
static string cnstJudgePath = ".\\";					//Judge's working path
static string cnstSOFileName = ".\\solution.out";		//Solution output filename.
static string cnstCOFileName = ".\\judgecompile.out";	//Judge complier's output filename.
static string cnstJFFileName = ".\\judge.cfg";			//Judge's default configuration filename.

//Details informations to solution's result.
char *cnstErrorInfo[100] = 
{
	"STATUS OK",
	"COMPLIE ERROR",
	"WRONG ANSWER",
	"TIME LIMIT EXCEED",
	"PRESENTATION ERROR",
	"OUTPUT LIMIT EXCEED",
	"RUNTIME ERROR",
	"MEMORY LIMIT EXCEED",
	"RESERVED",
	"RESERVED",
	"CONFIG FAULT",
	"SYSTEM FAULT"
};

//Enum type of all solution's result.
typedef enum SOULTION_RESULT
{
	STATUS_OK            = 0,
	COMPLIE_ERROR        = 1,
	WRONG_ANSWER         = 2,
	TIME_LIMIT_EXCEED    = 3,
	PRESENTATION_ERROR   = 4,
	OUTPUT_LIMIT_EXCEED  = 5,
	RUNTIME_ERROR        = 6,
	MEMORY_LIMIT_EXCEED  = 7,
	CONFIG_FAULT         = 10,
	SYSTEM_FAULT         = 11

}SOLUTION_RESULT;

//Read judge default configuration file
//set all parameters include language's configuration
bool ReadJudgeConfig(svector &vcComplieLine, 
					 svector &vcRunLine )
{
	fstream fileConfig;
	string strComplieLine, strRunLine;
	string strLangType, strExtra;
	
	fileConfig.open(cnstJFFileName.c_str(), ios::in);
	if( fileConfig.fail() )
		return false;

	// Read judge full path.
	getline(fileConfig, cnstJudgePath);

	// Read max output file size config.
	getline(fileConfig, strExtra);
	cnstMaxOutputFileSize = ::atoi(strExtra.c_str());

	/* Read solution run as username and password. */
	getline(fileConfig, strExtra);
	strcpy(szLoginUserName, strExtra.c_str());
	getline(fileConfig, strExtra);
	strcpy(szLoginPassword, strExtra.c_str());

	/* Read max-compiler timeout */
	getline(fileConfig, strExtra);
	cnstMaxCompileTime = ::atoi(strExtra.c_str());
/*
	Reserved module.
	// Read judge runtime level.
	getline(fileConfig, strExtra);
	cnstRuntimeLevel = ::atoi(strExtra.c_str());
*/
	// Read language config until file eof..
	while( getline(fileConfig, strExtra)
		&& getline(fileConfig, strComplieLine)
		&& getline(fileConfig, strRunLine) )
	{
		vcComplieLine.push_back( strComplieLine );
		vcRunLine.push_back( strRunLine );
	}

	fileConfig.close();

	return true;
}

//Compare solution's output file with standard output file
//return the details of result.
int CompareResult(char *szInputFileName, 
				  char *szSrcOutFileName, 
				  char *szDestOutFileName, 
				  int intProblemId, 
				  int isSpecialJudge )
{
	int intRetCode = STATUS_OK;

    if( isSpecialJudge )
	{
		char szCmdLine[MAX_PATH];
		SECURITY_ATTRIBUTES stProcessAttrib = {0};
		PROCESS_INFORMATION  stSubProcess = {0};
		STARTUPINFO  stSubStartup = {0};
		
		stProcessAttrib.nLength = sizeof(SECURITY_ATTRIBUTES);
		stProcessAttrib.lpSecurityDescriptor = NULL;
		stProcessAttrib.bInheritHandle = TRUE;
		
		stSubStartup.cb = sizeof(STARTUPINFO);
		stSubStartup.wShowWindow = SW_HIDE;
		stSubStartup.dwFlags = STARTF_USESHOWWINDOW;

		sprintf(szCmdLine, "spjs/%d.exe %s %s", intProblemId, szInputFileName, szDestOutFileName);

		// Create compare subprocess.
		if( !::CreateProcess( NULL, 
			szCmdLine,
			&stProcessAttrib,
			NULL,
			TRUE,
			NORMAL_PRIORITY_CLASS,
			NULL,
			NULL,
			&stSubStartup,
			&stSubProcess ) )
		{
			fprintf(stderr,"Create compare process fail, \npath:%s, \nLast Error : %d.\n", 
				szCmdLine,
				GetLastError() );

			return SYSTEM_FAULT;
		}
		if( WAIT_TIMEOUT == ::WaitForSingleObject(stSubProcess.hProcess, cnstMaxSpjTimeLimit) )
		{
			::TerminateProcess(stSubProcess.hProcess, 0);
			fprintf(stderr,"Compare process timeout, file: %s, \ntimelimit:%dms.\n", szCmdLine, cnstMaxSpjTimeLimit );
			return SYSTEM_FAULT;
		}
		DWORD dwExitCode = STATUS_OK;
		if( !::GetExitCodeProcess(stSubProcess.hProcess, &dwExitCode) )
		{
			fprintf(stderr,"Get compare process return code fail, file: %s.\n", szCmdLine );
			return SYSTEM_FAULT;
		}
		if( stSubProcess.hProcess != INVALID_HANDLE_VALUE )
			CloseHandle(stSubProcess.hProcess);
		if( dwExitCode != STATUS_OK && dwExitCode != PRESENTATION_ERROR && dwExitCode != WRONG_ANSWER  )
		{
			fprintf(stderr, "Special judge runtime error, return code:%d.\n", dwExitCode);
			return SYSTEM_FAULT;
		}
		intRetCode = dwExitCode;
	}
	else // Common comparation
	{
		fstream fileSrc, fileDest;
		string strLineSrc, strLineDest;

		fileSrc.open( szSrcOutFileName );
		fileDest.open( szDestOutFileName );
		if( fileSrc.fail() || fileDest.fail() )
		{
			fprintf(stderr,"Open compare files fail, src:%s, dest:%s\n", szSrcOutFileName,szDestOutFileName);
			return SYSTEM_FAULT;
		}

		intRetCode = STATUS_OK;
		while( true )
		{
			strLineSrc = "";
			while( getline(fileSrc, strLineSrc)
				&& strLineSrc.length() == 0 ) ;
			strLineDest = "";
			while( getline(fileDest, strLineDest)
				&& strLineDest.length() == 0 ) ;
			if( strLineSrc.length() == 0 && strLineDest.length() == 0 )		
				break;
			if( strLineSrc == strLineDest )
				continue;
			int intPos = (int)strLineDest.length() - 1;
			for(; intPos >= 0; intPos -- )
				if( strLineDest[ intPos ] != ' ' ) 
					break;
			strLineDest = strLineDest.substr(0, intPos + 1);
			if( strLineSrc == strLineDest )
				intRetCode = PRESENTATION_ERROR;
			else
			{
				intRetCode = WRONG_ANSWER;
				break;
			}
		}
	}

	return intRetCode;
}

int TerminateSubProcesses( DWORD dwParentProcessId )
{
	int intNum = 0;
	BOOL bOK = TRUE;
	PROCESSENTRY32 infoProcess;
	HANDLE hSnapshot = INVALID_HANDLE_VALUE;
	
	hSnapshot = ::CreateToolhelp32Snapshot( TH32CS_SNAPALL , 0 );
	if( hSnapshot == INVALID_HANDLE_VALUE )
	{
		JudgeDebug( printf( "error create snapshot,last error(%d).\n", GetLastError() ) );
		return 2;
	}
	intNum = 0;
	JudgeDebug( printf( "Parent Id:%u\n", dwParentProcessId ) );
	bOK = ::Process32First( hSnapshot, &infoProcess );
	while( bOK )
	{
		JudgeDebug( printf( "%s, parent id: %u, id:%u\n", 
			infoProcess.szExeFile, 
			infoProcess.th32ParentProcessID,
			infoProcess.th32ProcessID ) );
		if( infoProcess.th32ParentProcessID == dwParentProcessId )
		{
			HANDLE hProcess = ::OpenProcess( PROCESS_ALL_ACCESS, FALSE, infoProcess.th32ProcessID );
			if( hProcess == INVALID_HANDLE_VALUE )
			{
				JudgeDebug( printf( "error open process(id:%d),last error(%d).\n", 
					infoProcess.th32ProcessID, 
					GetLastError() ) );
				::CloseHandle( hSnapshot );
				return 1;
			}
			TerminateProcess( hProcess , 0 );
			JudgeDebug( printf( "Killed process(name:%s,id:%u).\n", infoProcess.szExeFile, infoProcess.th32ProcessID ) );
			intNum ++;
		}
		bOK = ::Process32Next( hSnapshot, &infoProcess );
	}

	CloseHandle( hSnapshot );
	
	return 0;
}

//Comple solution's source file with parameter command line.
//return the compile status.
int ComplieSolution(string &strComplieLine)
{
	PROCESS_INFORMATION  stSubProcess = {0};
	STARTUPINFO  stSubStartup = {0};
	SECURITY_ATTRIBUTES stProcessAttrib = {0};
	HANDLE hOutputFile = NULL;
	DWORD dwRetCode = 0;

	stProcessAttrib.nLength = sizeof(SECURITY_ATTRIBUTES);
	stProcessAttrib.lpSecurityDescriptor = NULL;
	stProcessAttrib.bInheritHandle = TRUE;

	hOutputFile = ::CreateFile((char *)cnstCOFileName.c_str(), 
		GENERIC_WRITE,
		FILE_SHARE_WRITE,
		&stProcessAttrib, 
		CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE,
		NULL );
	if( hOutputFile == INVALID_HANDLE_VALUE )
	{
		fprintf(stderr,"Create complie output file fail, Last Error: %d\n", GetLastError());
		return SYSTEM_FAULT;
	}

	stSubStartup.cb = sizeof(STARTUPINFO);
	stSubStartup.wShowWindow = SW_HIDE;
	stSubStartup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	stSubStartup.hStdOutput = hOutputFile;
	stSubStartup.hStdError  = hOutputFile;

	// Create compile subprocess.
	if( !::CreateProcess( NULL, 
		(char *)strComplieLine.c_str(),
		&stProcessAttrib,
		NULL,
		TRUE,
		NORMAL_PRIORITY_CLASS,
		NULL,
		NULL,
		&stSubStartup,
		&stSubProcess ) )
	{
		fprintf(stderr,"Create complie process fail, \npath:%s, \nLast Error : %d.\n", 
			strComplieLine.c_str(),
			GetLastError() );
		CloseHandle( hOutputFile );

		return SYSTEM_FAULT;
	}

	// Wait until complie subprocess exit.
	if( WAIT_TIMEOUT == ::WaitForSingleObject(stSubProcess.hProcess, cnstMaxCompileTime) )
	{
		JudgeDebug( printf( "Timeout for compiler with %dms.\n", cnstMaxCompileTime ) );
		TerminateSubProcesses( stSubProcess.dwProcessId ) ;
		TerminateProcess( stSubProcess.hProcess , 1 );
		CloseHandle( hOutputFile );
		return 1;
	}

	CloseHandle( hOutputFile );

	if( !GetExitCodeProcess( stSubProcess.hProcess, &dwRetCode ) )
	{
		fprintf(stderr,"Call exit code of complie subprocess fail, Last Error: %d\n", GetLastError());
		return SYSTEM_FAULT;
	}
	
	return dwRetCode ? COMPLIE_ERROR : STATUS_OK;
}

//Enable a privilege for current process.
BOOL EnablePrivilege(HANDLE hProcessToken, LPCSTR szPrivName)
{
	TOKEN_PRIVILEGES tkp = {0};

	if( !LookupPrivilegeValue( NULL,szPrivName,&tkp.Privileges[0].Luid ) )
	{
		return FALSE;
	}
	tkp.PrivilegeCount = 1;
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

	return AdjustTokenPrivileges( hProcessToken,FALSE,&tkp,0,NULL,NULL );
}

//Run the program generate by complier with user's solution.
//return details status of solution's result.
int RunSolution(string  &strRunLine, 
				int     intJudgeFiles,
				int     intProblemId,
				int     intMemoryLimit,
				int     &intMemoryUsed,
				int     intTimeLimit,
				int     &intTimeUsed,
				int     isSpecialJudge )
{
	char szJudgeIn[MAX_PATH], szJudgeOut[MAX_PATH];
	PROCESS_INFORMATION  stSubProcess = {0};
	STARTUPINFO  stSubStartup = {0};
	SECURITY_ATTRIBUTES stProcessAttrib = {0};
	HANDLE hInputFile , hOutputFile;
	PROCESS_MEMORY_COUNTERS stMemoryUsage;
	FILETIME tmCreation, tmExit, tmKernel, tmUser;
	HANDLE hLoginToken = INVALID_HANDLE_VALUE;
    int intRetCode = STATUS_OK, intTotalTimeUsed = 0, intTimeCircle = 10; //10ms
	DWORD dwExitCode = 0, dwOutputFileSize;

	//DWORD dwSameUserTimeCount, dwPreUserTime;

	stProcessAttrib.nLength = sizeof(SECURITY_ATTRIBUTES);
	stProcessAttrib.lpSecurityDescriptor = NULL;
	stProcessAttrib.bInheritHandle = TRUE;

	stSubStartup.cb = sizeof(STARTUPINFOW);
	stSubStartup.wShowWindow = SW_HIDE;

	stMemoryUsage.cb = sizeof(PROCESS_MEMORY_COUNTERS);

	intTimeLimit *= 10000; // 1s/100ns
	intMemoryLimit *= 1024; // 1KB
	intRetCode = STATUS_OK;
	intTimeUsed = 0, intMemoryUsed = 0, intTotalTimeUsed = 0;

#ifdef _LOGON_HNUJUDGE_USER_
	//Get SE_TCB_NAME right of current process.
	HANDLE hProcessToken ;

	if( !::OpenProcessToken( ::GetCurrentProcess(), 
		TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 
		&hProcessToken ) )
	{
		fprintf(stderr, "Open current process token for TOKEN_ADJUST_PRIVILEGES fail, last error : %d.\n", GetLastError());
		return SYSTEM_FAULT;
	}
	//Adjust the token privilege.
	if( !EnablePrivilege(hProcessToken, SE_TCB_NAME)
		|| !EnablePrivilege(hProcessToken, SE_ASSIGNPRIMARYTOKEN_NAME)
		|| !EnablePrivilege(hProcessToken, SE_INCREASE_QUOTA_NAME) )
	{
		fprintf(stderr, "Enable process SE_TCB_NAME or \
						SE_INCREASE_QUOTA_NAME or \
						SE_ASSIGNPRIMARYTOKEN_NAME privileges fail.\
						last error : %d.\n", GetLastError());

		return SYSTEM_FAULT;
	}
	CloseHandle(hProcessToken);

	//Logon as hnujudge user , to forbid the file access right to windows.
	if( !LogonUser(szLoginUserName, 
		NULL, 
		szLoginPassword, 
		LOGON32_LOGON_INTERACTIVE, 
		LOGON32_PROVIDER_DEFAULT ,
		&hLoginToken) )
	{
		fprintf(stderr, "Create user login token fail, last error : %d.\n", GetLastError());
		return SYSTEM_FAULT;
	}
	
#endif //_LOGON_HNUJUDGE_USER_

	for(int i = 0; i < intJudgeFiles && STATUS_OK == intRetCode ; i ++)
	{
		hOutputFile = ::CreateFile( (char *)cnstSOFileName.c_str(), 
			GENERIC_WRITE,
			FILE_SHARE_WRITE,
			&stProcessAttrib, 
			CREATE_ALWAYS,
			FILE_ATTRIBUTE_NORMAL,
			NULL );
		if( hOutputFile == INVALID_HANDLE_VALUE )
		{
			fprintf(stderr,"Create solution out file fail, Last Error: %d\n", GetLastError());
			return SYSTEM_FAULT;
		}

		sprintf(szJudgeIn, "data/%d/%d.std.in", intProblemId,  i + 1);
		sprintf(szJudgeOut, "data/%d/%d.std.out", intProblemId,  i + 1);

		hInputFile = ::CreateFile(szJudgeIn, 
			GENERIC_READ,
			FILE_SHARE_READ,
			&stProcessAttrib, 
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL );
		if( hInputFile == INVALID_HANDLE_VALUE )
		{
			fprintf(stderr,"Open judge in file fail, Last Error: %d, filename: %s\n", GetLastError(), szJudgeIn);
			return SYSTEM_FAULT;
		}

		stSubStartup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
		stSubStartup.hStdInput = hInputFile;
		stSubStartup.hStdOutput = hOutputFile;

#ifdef _LOGON_HNUJUDGE_USER_
		if( !::CreateProcessAsUser( hLoginToken,
			NULL,
			(char *)strRunLine.c_str(),
			&stProcessAttrib,
			NULL,
			TRUE,
			NORMAL_PRIORITY_CLASS,
			NULL,
			NULL,
			&stSubStartup,
			&stSubProcess ) )
		{
			fprintf(stderr,"Create solution subprocess as user fail, Last Error: %d\n", GetLastError());
			hOutputFile && CloseHandle( hOutputFile );
			hInputFile && CloseHandle( hInputFile );

			return SYSTEM_FAULT;
		}
#else
		if( !::CreateProcess( NULL,
			(char *)strRunLine.c_str(),
			&stProcessAttrib,
			NULL,
			TRUE,
			NORMAL_PRIORITY_CLASS,
			NULL,
			NULL,
			&stSubStartup,
			&stSubProcess ) )
		{
			fprintf(stderr,"Create solution subprocess fail, Last Error: %d\n", GetLastError());
			hOutputFile && CloseHandle( hOutputFile );
			hInputFile && CloseHandle( hInputFile );

			return SYSTEM_FAULT;
		}
#endif

//		dwPreUserTime = (DWORD)(-1);
//		dwSameUserTimeCount = 0;
		/* Wait for process in 10 milliseconds. */
		while( WAIT_TIMEOUT == ::WaitForSingleObject( stSubProcess.hProcess, intTimeCircle ) )
		{
			::GetProcessMemoryInfo( stSubProcess.hProcess, &stMemoryUsage , sizeof(PROCESS_MEMORY_COUNTERS) );
			intMemoryUsed = max(intMemoryUsed, (int)stMemoryUsage.WorkingSetSize);
			if( intMemoryUsed > intMemoryLimit )
			{
				fprintf(stderr,"Solution memory limit exceed for %dB with limit %B\n", 
					intMemoryUsed ,
					intMemoryLimit );
				intRetCode = MEMORY_LIMIT_EXCEED;

				break;
			}

			dwOutputFileSize = ::GetFileSize(hOutputFile, NULL);
			if( INVALID_FILE_SIZE == dwOutputFileSize )
			{
				fprintf(stderr,"Try to get solution output file size fail, Last Error : %d\n", GetLastError());
				intRetCode = SYSTEM_FAULT;

				break;
			}
			else if( dwOutputFileSize > (DWORD)cnstMaxOutputFileSize * 1024 )
			{
				fprintf(stderr, "Solution output file size limit exceed for output:%dB, with limit:%dB.",
					dwOutputFileSize , 
					cnstMaxOutputFileSize * 1024 );
				intRetCode = OUTPUT_LIMIT_EXCEED;

				break;
			}

			::GetProcessTimes( stSubProcess.hProcess, &tmCreation, &tmExit, &tmKernel, &tmUser ) ;
	 /*
	       if( dwPreUserTime == tmUser.dwLowDateTime )
				dwSameUserTimeCount ++;
			else
				dwSameUserTimeCount = 0;
			if( dwSameUserTimeCount > cnstRuntimeLevel )
			{
				fprintf(stderr,"TimeUsed:%d * 100ns round exceed in runtime level %d.\n", 
					dwPreUserTime,
					tmUser.dwLowDateTime,
					cnstRuntimeLevel );
				intRetCode = RUNTIME_ERROR;

				break;
			}
			dwPreUserTime = tmUser.dwLowDateTime;
	 */

			JudgeDebug( printf("MemoryUsed : %dB, TimeUsed:%d * 100ns,\n", 
				stMemoryUsage.WorkingSetSize, 
				tmUser.dwLowDateTime ) );
			
			if( intTimeUsed + (int)tmUser.dwLowDateTime > intTimeLimit )
			{
				fprintf(stderr,"Solution time limit exceed for %d * 100ns, with limt %d * 100ns \n", 
					intTimeUsed + (int)tmUser.dwLowDateTime, 
					intTimeLimit );
				intRetCode = TIME_LIMIT_EXCEED;

				break;
			}

			intTotalTimeUsed += intTimeCircle;
			if( intTotalTimeUsed > (intTimeLimit/10000) * 2 )
			{
				fprintf(stderr,"Solution time limit exceed for total %dms, with limt %d * 100ns \n", 
					intTotalTimeUsed, 
					intTimeLimit );

				intTimeUsed = intTotalTimeUsed * 10000;
				intRetCode = TIME_LIMIT_EXCEED;

				break;
			}
		}

		if( intRetCode != STATUS_OK )
		{
			intTimeUsed += (int)tmUser.dwLowDateTime;

			if( stSubProcess.hProcess != INVALID_HANDLE_VALUE )
			{
				::TerminateProcess( stSubProcess.hProcess, 0 );
				stSubProcess.hProcess = INVALID_HANDLE_VALUE;
			}
			break;
		}

#ifdef _STRICT_PROGRAM_
        if( !::GetExitCodeProcess(stSubProcess.hProcess, &dwExitCode) )
		{
			fprintf(stderr,"Call exit code of subprocess fail, Last Error: %d\n", GetLastError());
			intRetCode = SYSTEM_FAULT;
			break;
		}
#else
		dwExitCode = 0;
#endif

		::GetProcessMemoryInfo( stSubProcess.hProcess, &stMemoryUsage , sizeof(PROCESS_MEMORY_COUNTERS) );
		if( intMemoryUsed > intMemoryLimit )
		{
			fprintf(stderr,"Solution memory limit exceed for %dB with limit %B\n", 
				intMemoryUsed ,
				intMemoryLimit );
			intRetCode = MEMORY_LIMIT_EXCEED;
			break;
		}

		dwOutputFileSize = ::GetFileSize(hOutputFile, NULL);
		if( INVALID_FILE_SIZE == dwOutputFileSize )
		{
			fprintf(stderr,"Try to get solution output file size fail, Last Error : %d\n", GetLastError());
			intRetCode = SYSTEM_FAULT;
			break;
		}
		else if( dwOutputFileSize > (DWORD)cnstMaxOutputFileSize * 1024 )
		{
			fprintf(stderr, "Solution output file size limit exceed for output:%dB, with limit:%dB.",
				dwOutputFileSize , 
				cnstMaxOutputFileSize * 1024 );
			intRetCode = OUTPUT_LIMIT_EXCEED;
			break;
		}

		::GetProcessTimes( stSubProcess.hProcess, &tmCreation, &tmExit, &tmKernel, &tmUser );
		intMemoryUsed = max(intMemoryUsed, (int)stMemoryUsage.WorkingSetSize);
		tmUser.dwLowDateTime;

		intTimeUsed += (int)tmUser.dwLowDateTime;
		intMemoryUsed = max(intMemoryUsed, (int)stMemoryUsage.WorkingSetSize);

		if( intTimeUsed > intTimeLimit )
		{
			fprintf(stderr,"Solution time limit exceed for %d * 100ns, with limt %d * 100ns \n", 
				intTimeUsed = (int)tmUser.dwLowDateTime, 
				intTimeLimit );
			intRetCode = TIME_LIMIT_EXCEED;
			break;
		}

		if( stSubProcess.hProcess != INVALID_HANDLE_VALUE )
			CloseHandle(stSubProcess.hProcess);

		if( dwExitCode )
		{
			fprintf(stderr,"Solution exit code incorrect, code:%d\n", dwExitCode);
			intRetCode = RUNTIME_ERROR;
			break;
		}

		hOutputFile && CloseHandle( hOutputFile );
		hInputFile && CloseHandle( hInputFile );

		if( intRetCode != STATUS_OK )
			break;
		intRetCode = CompareResult(szJudgeIn, 
			szJudgeOut, 
			(char *)cnstSOFileName.c_str(), 
			intProblemId, 
			isSpecialJudge );
	}

	hOutputFile && CloseHandle( hOutputFile );
	hInputFile && CloseHandle( hInputFile );

	intMemoryUsed = (intMemoryUsed + 512) / 1024;
	intTimeUsed /= 10000;

	return intRetCode;
}

//Main symbol.
int main(int argc, char *argv[])
{
	svector vcComplieLine, vcRunLine;
	int intTimeLimit, intMemoryLimit, intMemoryUsed, intTimeUsed;
	int intRetCode, intLangId, intJudgeFiles, isSpecialJudge, intProblemId;

	if( argc < 7 )
	{
		fprintf(stderr,"Missing file arguments.\n");
		return CONFIG_FAULT;
	}

	// Set no error message box for this process and all it's subprocesses. 
	::SetErrorMode( SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS );

	intLangId = ::atoi(argv[1]);
	isSpecialJudge = ::atoi(argv[2]);
	intTimeLimit = ::atoi(argv[3]);
	intMemoryLimit = ::atoi(argv[4]);
	intJudgeFiles = ::atoi(argv[5]);
	intProblemId = ::atoi(argv[6]);

	if( !ReadJudgeConfig(vcComplieLine, vcRunLine) )
	{
		fprintf(stderr,"System configuration error : file open fail!\n"); 
		return CONFIG_FAULT;
	}

	if( intLangId >= (int)vcComplieLine.size() )
	{
		fprintf(stderr,"System configuration error : no such a complier!\n"); 
		return CONFIG_FAULT;
	}
	
	intRetCode = ComplieSolution(vcComplieLine[intLangId]);
	
	JudgeDebug( printf("Complie complete, OK , Return code %d\n", intRetCode) );
	
	if( intRetCode != STATUS_OK )
		return intRetCode;

	intRetCode = RunSolution( vcRunLine[intLangId],
		intJudgeFiles,
		intProblemId,
		intMemoryLimit,
		intMemoryUsed,
		intTimeLimit,
		intTimeUsed,
		isSpecialJudge );

	JudgeDebug( printf("Run solution complete, OK\n") );

	JudgeDebug( printf("Result : %s\nMemoryUsed: %dKB\nTime Used: %dMS\n", 
		cnstErrorInfo[intRetCode], 
		intMemoryUsed, 
		intTimeUsed ) );

	// Result output
	printf("%s\n%d\n%d\n", cnstErrorInfo[intRetCode], intMemoryUsed, intTimeUsed);

	return intRetCode ;
}
